#[macro_use]
extern crate log;

use dotenv::dotenv;
use sqlx::Pool;
use sqlx::{MySqlConnection};
use anyhow::Result;
use futures::executor::block_on;

mod field;
mod generate;
mod config;

use config::AppConfig;
use std::{thread, io};
use std::sync::mpsc;
use async_std::sync::Arc;
use chrono::{Local, NaiveDateTime};
use std::io::Write;
use crate::config::AboutSoft;


#[warn(non_snake_case)]
#[async_std::main]
async fn main() -> Result<()>{
    dotenv().ok();
    env_logger::init();

    info!("main...");

    let app_config = AppConfig::new();

    //let data_source= env::var("data_source").expect("DATABASE_URL is not set in .env file");
    // if(!dataSource.err().is_none()){
    //     warn!("DATABASE_URL is not set in .env file")
    // }
    // dataSource.expect("666");
    AboutSoft::print();
    app_config.print_config();

    //let mut pool = Pool::<MySqlConnection>::new(&env::var("DATABASE_URL")?).await?;
    let pool = Pool::<MySqlConnection>::builder()
        .min_size(2)
        .max_size(40).
        connect_timeout(std::time::Duration::from_secs(10)).
        max_lifetime(std::time::Duration::from_secs(1800)).
        idle_timeout(std::time::Duration::from_secs(600)).
        build(&app_config.data_source().clone()).await?;

    // 创建一个通道
    let (tx, rx): (mpsc::Sender<i64>, mpsc::Receiver<i64>) =mpsc::channel();


    //let pool=Builder::new().num_threads(num_cpus).thread_name(String::from("threadpool")).build();
    let app_cfg =Arc::new(app_config);
    let db_pool=Arc::new(pool);

    for _ in 0..app_cfg.thread_count() {
        let sender = tx.clone();
        let cfg = app_cfg.clone();
        let temp_db_pool = db_pool.clone();
        thread::spawn(move || {
            let resutl=generate::generate_data(&sender, &cfg, &temp_db_pool);
            block_on(resutl);
        });
    }
    let begin_time:NaiveDateTime = Local::now().naive_local();
    println!("## {} start...", begin_time);
    // 创建线程用于发送消息
    let recv_thread = thread::spawn(move || {
        // 发送一个消息， 此处是数字id
        let mut total = 0i64;
        let mut last_time =Local::now().naive_local();
        loop {
            let recv_count=rx.recv().unwrap();
            total+=recv_count;
            let now:NaiveDateTime = Local::now().naive_local();
            let dur = now - last_time;
            if dur.num_milliseconds() > 200 {
                last_time = now;
                let total_duration = now -begin_time;
                let per_num =if total_duration.num_seconds() < 1 {
                    total
                } else {
                    total / total_duration.num_seconds()
                };
                let mut  str_use_time =String::from("");
                if total_duration.num_seconds() < 60 {
                    str_use_time.push_str(&total_duration.num_seconds().to_string());
                    str_use_time.push_str("秒");
                }else if total_duration.num_minutes() <60 {
                    str_use_time.push_str(&total_duration.num_minutes().to_string());
                    str_use_time.push_str("分钟");
                    str_use_time.push_str(&(total_duration.num_seconds() % 60).to_string());
                    str_use_time.push_str("秒");
                }else if total_duration.num_hours() <24 {
                    str_use_time.push_str(&total_duration.num_hours().to_string());
                    str_use_time.push_str("小时");
                    str_use_time.push_str(&(total_duration.num_minutes() % 60).to_string());
                    str_use_time.push_str("分钟");
                }else {
                    str_use_time.push_str(&total_duration.num_days().to_string());
                    str_use_time.push_str("天");
                    str_use_time.push_str(&(total_duration.num_hours() % 24).to_string());
                    str_use_time.push_str("小时");
                }
                print!("\r{} 共生成:{}条, 每秒: {}条, 耗时: {}", now.format("%Y-%m-%d %H:%M:%S").to_string(), total, per_num, str_use_time);
                io::stdout().flush().unwrap();
            }


        }

    });
    recv_thread.join().unwrap();




    Ok(())
}